// // =============================================================================
// /**
//    @file 
//    Defines the fundamental @p call_center class
// */


// // =============================================================================
// //                                 C++ Headers
// #include <string>
// #include <sstream>
// #include <ctime>
// #include <list>
// #include <condition_variable>
// #include <thread>
// #include <memory>
// #include <cstdint>
	
// // =============================================================================
// //                                 3rds Headers


// // =============================================================================
// //                                 Our Headers

// #include <tenacitas_async/handlers.h>
// #include <tenacitas_async/event.h>




// // =============================================================================
// //                                 Namespaces
// using namespace std;

// // =============================================================================
// //                                 Macro Contants

// /**
//  */


// // =============================================================================
// //                                 Macro Commands


// /**
//    namespace of the organization
// */

// namespace tenacitas {
//     /**
//        namespace for the project
//     */
//     namespace distributed {
//         // =====================================================================
//         //                             Typedefs

//         /**
//          */


//         // =====================================================================
//         //                             Pre-Declarations


//         // =====================================================================
//         //                             Attributes

//         /**
//          */


//         // =====================================================================
//         //                             Functions

//         /**
//          */


//         // =====================================================================
//         //                             Classes


//         /** 

//             @nosubgrouping 
//         */
//         template <typename t_supplier>
//         class call_center {

//             // -----------------------------------------------------------------
//             //    call_center - Friends

//         public:

//             // -----------------------------------------------------------------
//             //    call_center - Public Internal Types

//             typedef t_supplier supplier_t;
            
//             typedef typename supplier_t::phone_t phone_t;

//             typedef typename phone_t::ptr_t phone_ptr_t;

//             typedef typename supplier_t::call_t call_t;

//             typedef typename supplier_t::attendant_t attendant_t;

//             typedef typename attendant_t::ptr_t attendant_ptr_t;

//             typedef typename supplier_t::attendant_allocator_t attendant_allocator_t;

//             typedef typename supplier_t::call_recorder_t call_recorder_t;

//             typedef typename async::event<call_t> call_event_t;

//             // -----------------------------------------------------------------
//             //    call_center - Public Constructors

//             call_center( phone_ptr_t p_phone );

//             /**
//                Destructor
//             */
//             ~call_center ( ) ;

//             // -----------------------------------------------------------------
//             //    call_center - Public Accessors
            

//             // -----------------------------------------------------------------
//             //    call_center - Public Helpers
            

//             // -----------------------------------------------------------------
//             //    call_center - Public Processors

//             /** */
//             void new_call( call_t && p_call );
                

//             // -----------------------------------------------------------------
//             //    call_center - Public Operators
            

//             // -----------------------------------------------------------------
//             //    call_center - Public Attributes
            


//         private:

//             // -----------------------------------------------------------------
//             //    call_center - Private Internal Types


//             struct handlers_supplier {
//                 typedef call_recorder_t logger_t;
//                 typedef call_event_t event_t;
//                 typedef attendant_t handler_t;
//                 typedef attendant_allocator_t handler_creator_t;
//             };

//             typedef async::handlers<handlers_supplier> calls_handlers_t;


//             // -----------------------------------------------------------------
//             //    call_center - Private Constructors
            

//             // -----------------------------------------------------------------
//             //    call_center - Private Accessors
            

//             // -----------------------------------------------------------------
//             //    call_center - Private Helpers
            

//             // -----------------------------------------------------------------
//             //    call_center - Private Processors
            

//             // -----------------------------------------------------------------
//             //    call_center - Private Operators
            

//             // -----------------------------------------------------------------
//             //    call_center - Private Attributes
            
//             phone_ptr_t m_phone;
            
//         };

//     }
// }



// // =============================================================================
// //                     I M P L E M E N T A T I O N
// // =============================================================================

// using namespace tenacitas::distributed;

// // -----------------------------------------------------------------------------
// template <typename t_supplier>
// call_center<t_supplier>::
// call_center( call_center<t_supplier>::phone_ptr_t p_phone )
//     : m_phone( p_phone ) { }

// // -----------------------------------------------------------------------------
// template <typename t_supplier>
// call_center<t_supplier>::
// ~call_center ( ) {}


// // -----------------------------------------------------------------------------
// template <typename t_supplier>
// void
// call_center<t_supplier>::
// new_call( call_center<t_supplier>::call_t && p_call ) {
    
//     calls_handlers_t::prt_t l_instance = calls_handlers_t::instance( );

//     l_instance->handle( call_event_t( m_phone, p_call ) );
// }



















//         // /**
//         //    @p call_center is responsible for receiving calls from customers, and
//         //    trying to allocate an agent to talk to the customer, who will provide 
//         //    some service. If no agent is available, the call will be on hold, and
//         //    other attempts to allocate an agent will eventually be made. 

//         //    call_center is type parameterized in order to let it highly
//         //    customizable, without losing performance.

//         //    -----------------------------------------------------------------
//         //    @tparam t_network is the physical media through which the calls
//         //    arrive.
//         //    It must implement:

//         //    A type that defines the type of pointer of the @p t_network
//         //    <tt>typedef ptr</tt>

//         //    A method that starts the @p t_nerwork to wait for calls in a
//         //    specified address
//         //    <tt>void start( const t_address & )</tt>
               
//         //    A method that waits for a call from a customer at the address
//         //    defined in @p start
//         //    <tt>t_call wait( )</tt>

//         //    A method that makes the network stop receiving calls
//         //    <tt>void stop( )</tt>

//         //    A method that will send a ciphered message to the client
//         //    <tt>void send( const string & )</tt>

//         //    A method that will receive a ciphered message from the client
//         //    <tt>string receive( )</tt>

//         //    -----------------------------------------------------------------
//         //    @tparam t_network_timeout defines how the network will deal with
//         //    delays in sending and receiving messages 

//         //    -----------------------------------------------------------------
//         //    @tparam t_address is the address where a customer should call to, in
//         //    order to reach the call center 

//         //    -----------------------------------------------------------------
//         //    @tparam t_on_hold_calls is responsible for keeping the calls that were
//         //    not answered by an agent yet

//         //    // -----------------------------------------------------------------
//         //    @tparam t_message_cipher is responsible for ciphering and deciphering
//         //    the messages that are received and sent in a call 

//         //    -----------------------------------------------------------------
//         //    @tparam t_message_coder is responsible for coding and decoding the
//         //    messages that are received and sent in a call 

//         //    -----------------------------------------------------------------
//         //    @tparam t_message is the original message sent by the customer.
//         //    It must implement:

//         //    Copy constructor
//         //    <tt>t_message( const t_message & )</tt>

//         //    Assignment communicator
//         //    <tt>t_message & communicator= ( t_message & );</tt>

//         //    -----------------------------------------------------------------
//         //    @tparam t_agent_allocator is responsible for allocating an @p t_agent
//         //    to serve the customer.
//         //    It must implement:

//         //    A type that defines the type of pointer of the @p t_agent_allocator.
//         //    <tt>typedef ptr;</tt>

//         //    A method that starts the @p t_agent_allocator
//         //    <tt>void start( )</tt>

//         //    A method that makes the agent allocator stop allocating any agents
//         //    <tt>void stop( );</tt>

//         //    -----------------------------------------------------------------
//         //    @tparam t_agent is reponsible for attending the call, receiving and 
//         //    (possibly) sending messages, in order to provide a service to the
//         //    customer.

//         //    -----------------------------------------------------------------
//         //    @tparam t_agent_timeout defines how the agents will handle with delays
//         //    in receiving messages
           
//         //    -----------------------------------------------------------------
//         //    @tparam t_call_recorder  is responsible for recording events that
//         //    might occurr in a call. 

//         //    It must implement:
//         //    <tt>
//         //    A type that defines the type of pointer of the logger.
//         //    typedef ptr;

//         //    A method that will log, if the log level is debug, a @p p_msg,
//         //    identifying that the log happened at line @p p_line, at file @p
//         //    p_file, in function @p p_function. 
//         //    <tt>void debug( const char * p_file, const char * p_function,
//         //    uint32_t p_line, const char * p_msg );</tt>

//         //    A method that will log, if the log level is warning, a @p p_msg,
//         //    identifying that the log happened at line @p p_line, at file @p
//         //    p_file, in function @p p_function.    
//         //    <tt>void warn( const char * p_file, const char * p_function,
//         //    uint32_t p_line, const char * p_msg );</tt>

//         //    A method that will log, if the log error is error, a @p p_msg,
//         //    identifying that the log happened at line @p p_line, at file @p
//         //    p_file, in function @p p_function.    
//         //    <tt>void error( const char * p_file, const char * p_function,
//         //    uint32_t p_line, const char * p_msg );</tt>

//         //    A method that will log a @p p_msg identifying that the log
//         //    happened at line @p p_line, at file @p p_file, in function @p
//         //    p_function. After logging a message in this level, the @p
//         //    call_center will stop working. 
//         //    <tt>void critical( const char * p_file, const char * p_function,
//         //    uint32_t p_line, const char * p_msg );</tt>




//         //    When a @p  call_center object is created, it is in the @p stopped
//         //    state. In order to make it work, one must call the @p start method. If
//         //    it becomes necessary to put it back in the @p stopped state, it is
//         //    necessary to call the @p stop method.

//         //    If it is desired to change the @p t_address where the @p
//         //    call_center receives calls, call the @p address method. It will
//         //    call @p stop the @p  call_center, set a new @p t_address, and call
//         //    @p start again. 
//         // */
//         // template <typename t_call,
//         //           typename t_phone_company,
//         //           typename t_phone_number,
//         //           typename t_attendants,
//         //           typename t_attendant,
//         //           typename t_on_hold_calls,
//         //           typename t_recorder>
//         // class  call_center {
//         // public:
//         //     // -----------------------------------------------------------------
//         //     //     call_center - Public Internal Types

//         //     typedef shared_ptr<call_center> ptr;
            
//         //     typedef t_phone_company phone_company_type;

//         //     typedef typename phone_company_type::ptr phone_company_ptr;

//         //     typedef t_phone_number phone_number_type;

//         //     typedef t_call call_type;

//         //     typedef typename call_type::ptr call_ptr;

//         //     typedef t_attendants attendants_type;

//         //     /** Type of pointer for the @p attendants */
//         //     typedef typename attendants_type::ptr attendants_ptr;

//         //     typedef t_attendant attendant_type;

//         //     typedef typename attendant_type::ptr attendant_ptr;

//         //     typedef t_recorder recorder_type;
            
//         //     /** Type of pointer for the @p logger */
//         //     typedef typename recorder_type::ptr recorder_ptr;

//         //     typedef t_on_hold_calls on_hold_calls_type;

//         //     /** Type of pointer for the @p on-hold calls */
//         //     typedef typename on_hold_calls_type::ptr on_hold_calls_ptr;

            
//         //     // -----------------------------------------------------------------
//         //     //     call_center - Public Constructors
        
//         //     /** Constructor
//         //         @param [in] p_phone_company is the physical media through which the
//         //         calls  arrive

//         //         @param [in] p_phone_number is the phone_number where the clients call the
//         //         assistance center 

//         //         @param [in] p_recorder is responsible for recording events
//         //         that might occurr in a call
//         //     */
//         //     call_center( std::uint16_t p_num_extensions,
//         //                  phone_company_ptr p_phone_company,
//         //                  const phone_number_type & p_phone_number,
//         //                  attendants_ptr p_attendants,
//         //                  on_hold_calls_ptr p_on_hold_calls,
//         //                  recorder_ptr p_recorder )
//         //         : m_phone_company( p_phone_company ),
//         //           m_phone_number( p_phone_number ),
//         //           m_attendants( p_attendants ),
//         //           m_on_hold_calls( p_on_hold_calls ),
//         //           m_recorder( p_recorder ),
//         //           m_state( stopped_state ),
//         //           m_answer_on_hold_calls( ),
//         //           m_extensions( new extensions_type( p_num_extensions,
//         //                                              p_recorder,
//         //                                              m_attendants,
//         //                                              m_phone_company ) ) {

//         //         rec_in( m_recorder );

//         //         start( );
                
//         //         rec_out( m_recorder );
//         //     }


//         //     /** Destructor
//         //         Stops the call center
//         //     */
//         //     ~call_center( ) {
//         //         rec_in( m_recorder );

//         //         stop( );

//         //         rec_out( m_recorder );
//         //     }
                
//         //     // -----------------------------------------------------------------
//         //     //     call_center - Public Accessors

//         //     /** Identifies if the call center is stopped */
//         //     bool stopped( ) const  { return ( m_state == stopped_state ); }

//         //     /** Identifies if the call center has started */
//         //     bool started( ) const  { return ( m_state == started_state ); }


//         //     // -----------------------------------------------------------------
//         //     //     call_center - Public Processors
            
//         //     /** Tries to answer new calls */
//         //     void new_call( call_ptr p_call ) {

//         //         rec_in( m_recorder );
                
//         //         rec_debug( m_recorder, "new call received" );
//         //         p_call->received( );

//         //         try_to_answer( p_call );

//         //         rec_out( m_recorder );
//         //     }

//         // private:

//         //     // -----------------------------------------------------------------
//         //     //     call_center - Private Internal Types

//         //     /** The possible states of the  call_center */
//         //     typedef enum  { stopped_state, started_state } state;

//         //     typedef extension<recorder_type,
//         //                       attendant_type,
//         //                       phone_company_type> extension_type;

//         //     typedef typename extension_type::ptr extension_ptr;

//         //     typedef extensions<recorder_type,
//         //                        attendant_type,
//         //                        phone_company_type> extensions_type; 

//         //     typedef typename extensions_type::ptr extensions_ptr;

//         //     typedef typename extensions_type::position extensions_position;

//         //     typedef call_center<t_phone_company,
//         //                         t_call,
//         //                         t_phone_number,
//         //                         t_attendants,
//         //                         t_attendant,
//         //                         t_on_hold_calls,
//         //                         t_recorder> call_center_type;

                        
//         //     // -----------------------------------------------------------------
//         //     //     call_center - Private Constructors
            
//         //     call_center( );

//         //     call_center( const call_center & );

//         //     // -----------------------------------------------------------------
//         //     //     call_center - Private Processors

//         //     /** Starts the call center */
//         //     void start( ) {
//         //         rec_in( m_recorder );

//         //         if ( started( ) ) {
//         //             rec_warn( m_recorder,
//         //                       "attempt to start a call_center already started" );
//         //         }
//         //         else {

//         //             rec_debug( m_recorder, "call_center started" );
//         //             m_state = started_state;
                    
//         //             rec_debug( m_recorder, "starting the components" );
//         //             start_components( );
                    
//         //         }
//         //         rec_out( m_recorder );
//         //     }

//         //     /** Stops the call center */
//         //     void stop( ) {
//         //         rec_in( m_recorder );

//         //         if ( stopped( ) ) {
//         //             rec_warn( m_recorder,
//         //                       "attempt to stop a call_center already stopped" );
//         //         }
//         //         else {                        
//         //             rec_debug( m_recorder, "stopping the components" );

//         //             stop_components( );

//         //             rec_debug( m_recorder, "call_center stopped" );
//         //             m_state = stopped_state;
//         //         }

//         //         rec_out( m_recorder );    
//         //     }

//         //     void start_components( ) {

//         //         rec_in( m_recorder );


//         //         // rec_debug( m_recorder, "starting the on-hold calls" );
//         //         // m_on_hold_calls->start( m_recorder );

//         //         // rec_debug( m_recorder, "starting thread to awnser on-hold calls" );
//         //         // m_answer_on_hold_calls =
//         //         //     std::thread( &call_center_type::answer_on_hold_calls,
//         //         //                  this );
                
//         //         rec_out( m_recorder );
//         //     }


//         //     /** Tries to stop all components for the call center to operate */
//         //     void stop_components( ) {
//         //         rec_in( m_recorder );

//         //         if ( m_answer_on_hold_calls.get_id() != std::thread::id( ) ) {
//         //             rec_debug( m_recorder, "Stopping awnsering on-hold calls" );
//         //             m_answer_on_hold_calls.join( );
//         //         }
//         //         else  {
//         //             rec_debug( m_recorder,
//         //                        "awnsering on-hold calls thread "
//         //                        "already stopped" );
//         //         }

//         //         rec_debug( m_recorder,
//         //                    "waiting for all the on-going calls to finish" );
//         //         m_extensions->stop( );
                
//         //         // rec_debug( m_recorder, "Stopping the on hold calls list" );
//         //         // m_on_hold_calls->stop( );

//         //         rec_out( m_recorder );
//         //     }


//         //     /** Tries to answer calls that were previously put on-hold */
//         //     void answer_on_hold_calls( ) {
//         //         rec_in( m_recorder );

//         //         while ( true ) {

//         //             if ( stopped( ) ) {
//         //                 rec_info( m_recorder, "call_center stopped" );
//         //                 break;
//         //             }
                    
//         //             call_ptr l_call;

//         //             rec_debug( m_recorder, "removing a call from on-hold" );
//         //             l_call = m_on_hold_calls->remove( );

//         //             rec_debug( m_recorder, "call removed from on-hold" );
//         //             l_call->out_of_on_hold( );

//         //             try_to_answer( l_call );                        
//         //         }

//         //         rec_out( m_recorder );
//         //     }


//         //     /** */
//         //     bool free_extension( extensions_position & p_pos ) {
//         //         rec_in( m_recorder );
                
//         //         bool l_res = true;
                
//         //         if ( !m_extensions->find_available( p_pos ) ) {
//         //             rec_warn( m_recorder, "no extensions free" );
//         //             attendant_ptr l_attendant = m_attendants->find( );
//         //             if ( l_attendant ) {
//         //                 extension_ptr l_extension
//         //                     (new extension_type( l_attendant,
//         //                                          m_phone_company,
//         //                                          m_recorder ) );
//         //                 p_pos = m_extensions->add( l_extension );
//         //             }
//         //             else {
//         //                 rec_warn( m_recorder, "unable to find an "
//         //                           "available attendant" );
//         //                 l_res = false;                        
//         //             }
//         //         }
//         //         rec_out( m_recorder );
//         //         return l_res;
//         //     }
            
//         //     /** Tries to answer a call */
//         //     void try_to_answer( call_ptr p_call ) {

//         //         rec_in( m_recorder );

//         //         p_call->trying_to_answer( );

//         //         extensions_position l_extension_position;;
                
//         //         if ( !free_extension( l_extension_position ) ) {
//         //             rec_debug( m_recorder, "no available extension" );
//         //             p_call->into_on_hold( );
//         //             m_on_hold_calls->add( p_call );
//         //         }
//         //         else {
//         //             rec_debug( m_recorder, "found an available extension" );
//         //             extension_ptr l_extension = *l_extension_position;
//         //             l_extension->accept( p_call,
//         //                                  m_extensions,
//         //                                  l_extension_position );
//         //         }
                
//         //         rec_out( m_recorder );
//         //     }

            
//         //     // -----------------------------------------------------------------
//         //     //     call_center - Private Attributes

//         //     /** physical media through which the calls arrive */     
//         //     phone_company_ptr m_phone_company;

//         //     /** phone_number where the clients call the assistance center */
//         //     phone_number_type m_phone_number;

//         //     /** responsible for finding an available attendant */
//         //     attendants_ptr m_attendants;

//         //     /** responsoble for manageing on-hold calls */
//         //     on_hold_calls_ptr m_on_hold_calls;

//         //     /** responsible for logging messages */
//         //     recorder_ptr m_recorder;

//         //     /** indicates the current state of the call center */
//         //     state m_state;

//         //     /** thread that removes a call from the on-hold list, and tries that
//         //         the attendants answer it */
//         //     std::thread m_answer_on_hold_calls;

//         //     /** */
//         //     extensions_ptr m_extensions;

//         // };
